package cn.tedu.mall.order.service.impl;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.pojo.domain.CsmallAuthenticationInfo;
import cn.tedu.mall.common.restful.JsonPage;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.order.mapper.OmsOrderItemMapper;
import cn.tedu.mall.order.mapper.OmsOrderMapper;
import cn.tedu.mall.order.service.IOmsCartService;
import cn.tedu.mall.order.service.IOmsOrderService;
import cn.tedu.mall.order.utils.IdGeneratorUtils;
import cn.tedu.mall.pojo.order.dto.OrderAddDTO;
import cn.tedu.mall.pojo.order.dto.OrderItemAddDTO;
import cn.tedu.mall.pojo.order.dto.OrderListTimeDTO;
import cn.tedu.mall.pojo.order.dto.OrderStateUpdateDTO;
import cn.tedu.mall.pojo.order.model.OmsCart;
import cn.tedu.mall.pojo.order.model.OmsOrder;
import cn.tedu.mall.pojo.order.model.OmsOrderItem;
import cn.tedu.mall.pojo.order.vo.OrderAddVO;
import cn.tedu.mall.pojo.order.vo.OrderDetailVO;
import cn.tedu.mall.pojo.order.vo.OrderListVO;
import cn.tedu.mall.product.service.order.IForOrderSkuService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@DubboService //将来要被秒杀模块调用
@Service
@Slf4j
public class OmsOrderServiceImpl implements IOmsOrderService {
    //远程调用product模块进行库存减少
    @DubboReference
    private IForOrderSkuService dubboSkuService;
    //删除购物车
    @Autowired
    private IOmsCartService omsCartService;
    //新增订单
    @Autowired
    private OmsOrderMapper orderMapper;
    //新增订单项
    @Autowired
    private OmsOrderItemMapper omsOrderItemMapper;

    //新增订单，通过分析可以发现，新增订单需要涉及到库存减少，购物车删除等操作，跨数据库、跨应用程序，保证分布式事务
    //该方法就是这个事务的起点--TM
    @GlobalTransactional
    @Override
    public OrderAddVO addOrder(OrderAddDTO orderAddDTO) {
        //第一部分:收集信息，准备数据
        OmsOrder omsOrder = new OmsOrder();
        BeanUtils.copyProperties(orderAddDTO,omsOrder);
        //收集信息和计算的操作，单独编写成一个方法
        loadOrder(omsOrder);
        //收集订单项信息
        List<OrderItemAddDTO> orderItemAddDTOs = orderAddDTO.getOrderItems();
        //判断订单项是否为null，为null直接抛出异常
        if(orderItemAddDTOs==null)
            throw  new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"订单中必须包含订单项");
        //准备List<OmsOrderItme>对象
        List<OmsOrderItem> omsOrderItems = new ArrayList<>();
        //遍历订单项，转成omsOrderItems
        for (OrderItemAddDTO orderItemAddDTO : orderItemAddDTOs) {
            //需要将orderItemAddDTO转成orderItem
            OmsOrderItem omsOrderItem = new OmsOrderItem();
            BeanUtils.copyProperties(orderItemAddDTO,omsOrderItem);
            //针对omsOrderItem对象进行一些属性的非空判断
            loadOrderItem(omsOrderItem);
            //将omsOrder中orderId赋值给omsOrderItem
            omsOrderItem.setOrderId(omsOrder.getId());
            //将omsOrderItem保存到对应的集合中
            omsOrderItems.add(omsOrderItem);
            //订单信息已经收集完毕，接下来进行第二部分：完成数据库的操作
            //减少商品库存
            //获取skuId
            Long skuId = omsOrderItem.getSkuId();
            int rows = dubboSkuService.reduceStockNum(skuId, omsOrderItem.getQuantity());
            //判断影响行数
            if(rows==0){
                log.info("商品{},库存不足",skuId);
                //减少库存失败，没有库存
                throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"库存不足");
            }
            //删除购物车信息
            OmsCart omsCart = new OmsCart();
            omsCart.setUserId(omsOrder.getUserId());
            omsCart.setSkuId(skuId);
            omsCartService.removeUserCarts(omsCart);
        }
        //新增订单
        orderMapper.insertOrder(omsOrder);
        //新增订单项
        omsOrderItemMapper.insertOrderItems(omsOrderItems);
        //准备返回类型对象
        OrderAddVO orderAddVO = new OrderAddVO();
        orderAddVO.setId(omsOrder.getId()); //订单id
        orderAddVO.setSn(omsOrder.getSn()); //订单编号
        orderAddVO.setCreateTime(omsOrder.getGmtCreate()); //订单生成时间
        orderAddVO.setPayAmount(omsOrder.getAmountOfActualPay()); //实际支付金额
        //最后千万不要忘记返回
        return orderAddVO;
    }
    //针对订单项信息的收集
    private void loadOrderItem(OmsOrderItem omsOrderItem) {
        if(omsOrderItem.getId()==null){
            Long id = IdGeneratorUtils.getDistributeId("order_item");
            omsOrderItem.setId(id);
        }
        if(omsOrderItem.getSkuId()==null){
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"订单商品中必须包含skuId");
        }
    }

    //新增订单中，需要收集和计算order对象信息
    private void loadOrder(OmsOrder omsOrder) {
        //针对order对象中必须具备但是为null的值进行赋值
        //判断id是否为null
        if(omsOrder.getId()==null){
            //利用Leaf生成分布式id
            Long id = IdGeneratorUtils.getDistributeId("order");
            omsOrder.setId(id);
        }
        //判断订单编号是否为null
        if(omsOrder.getSn()==null){
            //生成随机字符串当成sn
            String sn = UUID.randomUUID().toString();
            omsOrder.setSn(sn);
        }
        //判断用户id是否为null
        if(omsOrder.getUserId()==null){
            Long userId = getUserId();
            omsOrder.setUserId(userId);
        }
        //订单状态是否为null，默认是0
        if(omsOrder.getState()==null){
            omsOrder.setState(0);
        }
        //为了保证生成订单的时间和数据创建的时间以及最后修改的时间一致，我们手动赋值
        if(omsOrder.getGmtOrder()==null || omsOrder.getGmtCreate()==null || omsOrder.getGmtModified()==null){
            LocalDateTime now = LocalDateTime.now();
            omsOrder.setGmtOrder(now);
            omsOrder.setGmtCreate(now);
            omsOrder.setGmtModified(now);
        }
        //计算支付金额之前首先保证原价不能为null，原价为null直接抛出异常
        //运费为null，设置为0; 优惠为null，设置为0  方便计算
        if(omsOrder.getAmountOfOriginalPrice()==null)
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"订单必须要有原价");
        if(omsOrder.getAmountOfFreight()==null)
            omsOrder.setAmountOfFreight(new BigDecimal(0.0));
        if(omsOrder.getAmountOfDiscount()==null)
            omsOrder.setAmountOfDiscount(new BigDecimal(0.0));
        //计算实际支付金额（实际支付金额=原价+运费-优惠）
        BigDecimal originalPrice = omsOrder.getAmountOfOriginalPrice();
        BigDecimal freight = omsOrder.getAmountOfFreight();
        BigDecimal discount = omsOrder.getAmountOfDiscount();
        BigDecimal actualPrice = originalPrice.add(freight).subtract(discount);
        //将实际支付的金额赋值到omsOrder中
        omsOrder.setAmountOfActualPay(actualPrice);
    }

    @Override
    public void updateOrderState(OrderStateUpdateDTO orderStateUpdateDTO) {
        OmsOrder omsOrder = new OmsOrder();
        BeanUtils.copyProperties(orderStateUpdateDTO,omsOrder);
        orderMapper.updateOrderById(omsOrder);

    }
    //按照指定时间进行分页查询
    @Override
    public JsonPage<OrderListVO> listOrdersBetweenTimes(OrderListTimeDTO orderListTimeDTO) {
        //默认查询最近一个月的订单，所以orderListTimeDTO参数对象中的起始时间和结束时间只要有一个为null，就需要设置默认值
        //不为空，也要判断时间是否合理
        validaTimeAndLoadTime(orderListTimeDTO);
        //获取用户id
        Long userId = getUserId();
        orderListTimeDTO.setUserId(userId);
        //设置分页条件
        PageHelper.startPage(orderListTimeDTO.getPage(),orderListTimeDTO.getPageSize());
        //执行查询
        List<OrderListVO> orderListVOS = orderMapper.selectOrdersByTimes(orderListTimeDTO);
        return JsonPage.restPage(new PageInfo<>(orderListVOS));
    }

    private void validaTimeAndLoadTime(OrderListTimeDTO orderListTimeDTO) {
        //取出时间
        LocalDateTime startTime = orderListTimeDTO.getStartTime();
        LocalDateTime endTime = orderListTimeDTO.getEndTime();
        //起始时间和结束时间只要有一个为null，就需要设置默认值
        if(startTime==null || endTime==null){
            //起始时间就是当前时间减去一个月
            startTime = LocalDateTime.now().minusMonths(1);
            //结束时间就是当前时间
            endTime = LocalDateTime.now();

            orderListTimeDTO.setStartTime(startTime);
            orderListTimeDTO.setEndTime(endTime);
        }else{
            //检查startTime是否小于endTime
            if(endTime.toInstant(ZoneOffset.of("+8")).toEpochMilli()
                    < startTime.toInstant(ZoneOffset.of("+8")).toEpochMilli()){
                //结束时间小于起始时间，不合理，抛出异常
                throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"结束时间应该大于起始时间");
            }
        }
    }

    @Override
    public OrderDetailVO getOrderDetail(Long id) {
        return null;
    }
    //我们单独写一个方法获取用户信息
    public CsmallAuthenticationInfo getUserInfo(){
        //获取SpringSecurity上下文，获取token
        UsernamePasswordAuthenticationToken token =
                (UsernamePasswordAuthenticationToken)
                        SecurityContextHolder.getContext().getAuthentication();
        //判断token是否为null
        if(token==null)
            throw new CoolSharkServiceException(ResponseCode.UNAUTHORIZED,"没有登录信息");
        //获取用户信息
        CsmallAuthenticationInfo userInfo =
                (CsmallAuthenticationInfo) token.getCredentials();
        //返回登录用户信息
        return userInfo;
    }
    //单独写一个获取userId的方法
    public Long getUserId(){
        return getUserInfo().getId();
    }
}
